
#import "WW3DSquishySphere.h"
#import "RIBTransformBegin.h"
#import "RIBScale.h"
#import "RIBSphere.h"
#import "RIBTransformEnd.h"
#import "WWSample.h"
#import "WWEveParser.h"
#import "WW3DAttributeState.h"

@implementation WW3DSquishySphere

+ initialize { return [WW3DSquishySphere setVersion:1], self; }

- init
{
  [super init];

  radius = 1.0;
  zMin = -1.0;
  zMax =  1.0;
  xScale = yScale = zScale = 1.0;
  
  return self;
}


- awake
{
    [super awake];
    return self;
}


- setYScale:(RtFloat)newYScale
{
   yScale = newYScale;
   xScale = zScale = 1./pow((double)yScale, (double)(1./3.));
   return self;
}

- setRadius:(RtFloat)newRadius 
     zMin:(RtFloat)newZMin zMax:(RtFloat)newZMax 
     thetaMax:(RtFloat)newThetaMax yScale:(RtFloat)newYScale
     n:(int)newN tokens:(RtToken *)newTokens parms:(RtPointer *)newParms archiveVector:(char **)newArchiveVector
     printfTypeVector:(int *)newPrintfTypeVector printfNVector:(int *)newPrintfNVector
{  
   id  sphereObj;


   radius = newRadius;
   zMin = newZMin;
   zMax = newZMax;
   thetaMax = newThetaMax;
   [self setYScale:newYScale];

   [ribCommandList empty];

   sphereObj = [[RIBSphere alloc] init]; 
   [sphereObj setRadius:radius zMin:zMin zMax:zMax thetaMax:thetaMax
                    n:newN tokens:newTokens parms:newParms 
                    archiveVector:newArchiveVector 
                    printfTypeVector:newPrintfTypeVector printfNVector:newPrintfNVector];
   [sphereObj setMyShape:myShape];

   [ribCommandList insertObject:sphereObj at:0];
   [ribCommandList insertObject:[[[[RIBScale alloc] init] setSX:xScale sy:yScale sz:zScale] setMyShape:myShape] at:0];
   [ribCommandList insertObject:[[[RIBTransformBegin alloc] init] setMyShape:myShape] at:0];
   [ribCommandList addObject:[[[RIBTransformEnd alloc] init] setMyShape:myShape]];

   dirtyBoundingBox = TRUE;
  
   return self;
}

- (RtFloat)radius { return radius; } 
- (RtFloat)yScale { return yScale; }
- (RtFloat)zMin { return zMin; }
- (RtFloat)zMax { return zMax; }
- (RtFloat)thetaMax { return thetaMax; }

- _setRadius:(RtFloat)newRadius 
     zMin:(RtFloat)newZMin zMax:(RtFloat)newZMax 
     thetaMax:(RtFloat)newThetaMax yScale:(RtFloat)newYScale
{  
   radius = newRadius;
   zMin = newZMin;
   zMax = newZMax;
   thetaMax = newThetaMax;
   [self setYScale:newYScale];

   dirtyBoundingBox = TRUE;
  
   return self;
}

// WavesWorld archiving:
// writeEve:(NXStream *)stream
// writeScene:(NXStream *)stream

- lerpWith:b by:(float)uValue
{
   id  newMe;  


   if (([self class] != [b class]) || (uValue <= 0.0))
   {  return self;
   }

   if (uValue >= 1.0)
   {  return b;
   }

   newMe = [super lerpWith:b by:uValue]; // this will copy the RIBCommandList
   [newMe _setRadius:([self radius] + (([b radius] - [self radius]) * uValue))
              zMin:([self zMin] + (([b zMin] - [self zMin]) * uValue))
              zMax:([self zMax] + (([b zMax] - [self zMax]) * uValue))
              thetaMax:([self thetaMax] + (([b thetaMax] - [self thetaMax]) * uValue))
              yScale:([self yScale] + (([b yScale] - [self yScale]) * uValue))];

   return newMe;
}

- lerpSelfWith:b by:(float)uValue
{
   if (([self class] != [b class]) || (uValue <= 0.0))
   {  return self;
   }

   if (uValue >= 1.0)
   {  return b;
   }

   [super lerpWith:b by:uValue]; // this will copy the RIBCommandList
   [self _setRadius:([self radius] + (([b radius] - [self radius]) * uValue))
              zMin:([self zMin] + (([b zMin] - [self zMin]) * uValue))
              zMax:([self zMax] + (([b zMax] - [self zMax]) * uValue))
              thetaMax:([self thetaMax] + (([b thetaMax] - [self thetaMax]) * uValue))
              yScale:([self yScale] + (([b yScale] - [self yScale]) * uValue))];

   return self;
}

- writeEve:(NXStream *)stream atTabLevel:(int)tab
{
    int  i;
    
    for (i = 0; i < tab; i++) {
	NXPrintf(stream, "\t");
    }
    NXPrintf(stream, "WW3DSquishySphere %f %f %f %f", radius, zMin, zMax, thetaMax, yScale);
    return self;
}

- writeScene:(NXStream *)stream atTabLevel:(int)tab
{
    int  i;
    
    for (i = 0; i < tab; i++) {
	NXPrintf(stream, "\t");
    }
    NXPrintf(stream, "WW3DSquishySphere %f %f %f %f", radius, zMin, zMax, thetaMax, yScale);
    return self;
}

- write3DTextScene:(NXStream *)stream atTabLevel:(int)tab index:(int)index time:(float)time until:(float)lastTime
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }

   NXPrintf(stream, "startShape %s; ", [[self class] name]);
   // need tab
   // need index (position in current list)
   NXPrintf(stream, 
	    "EveCmd {Translate [expr { %d * $__text__(tabLength)}] [expr {$__text__(spacingFactor) * %d * $__text__(spacing) * $__text__(fontSize)}] 0 };\n", 
            tab, index); 
   NXPrintf(stream, "  EveCmd {WW3DText $__text__(fontName) $__text__(fontSize) {");
   [self writeEve:stream atTabLevel:tab];
   NXPrintf(stream, "} left;}\n");
  NXPrintf(stream, "endShape;\n");

  return self;
}

- writeInventorAtTime:(float)currentTime to:(NXStream *)stream atTabLevel:(int)tab
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "# ");
   [self writeEve:stream atTabLevel:tab];
   NXPrintf(stream, "\n");

   return [ribCommandList writeInventorAtTime:currentTime to:stream atTabLevel:tab];
}

#define typeVector "ffff"
#define typeValues &radius, &zMin, &zMax, &yScale

- read:(NXTypedStream *)stream 
{
    int version;
    
    [super read:stream];
    version = NXTypedStreamClassVersion(stream,"WW3DSquishySphere");
    if (version == 0) NXReadTypes(stream, "i", &version), version = 1;
    if (version == 1)
    {  NXReadTypes(stream, typeVector, typeValues);
       xScale = zScale = 1./sqrt((double)yScale);
    }

    return self;
}

- write:(NXTypedStream *)stream 
{
    [super write:stream];
    NXWriteTypes(stream, typeVector, typeValues);
    return self;
}

- (BOOL)theSameAs:otherRIBCommand
{
  if (radius != [otherRIBCommand radius])
  {  return NO;
  }
  if (yScale != [otherRIBCommand yScale])
  {  return NO;
  }
  if (zMin != [otherRIBCommand zMin])
  {  return NO;
  }
  if (zMax != [otherRIBCommand zMax])
  {  return NO;
  }
  if (thetaMax != [otherRIBCommand thetaMax])
  {  return NO;
  }
  return [super theSameAs:otherRIBCommand];
}

@end
